package edu.stanford.bmir.protege.web.server.stkosutil.visualizer;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONObject;

import org.semanticweb.owlapi.model.EntityType;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAnnotationProperty;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassAssertionAxiom;
import org.semanticweb.owlapi.model.OWLDataProperty;
import org.semanticweb.owlapi.model.OWLDatatype;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLEntityVisitor;
import org.semanticweb.owlapi.model.OWLIndividual;
import org.semanticweb.owlapi.model.OWLNamedIndividual;
import org.semanticweb.owlapi.model.OWLObjectProperty;

import edu.stanford.bmir.protege.web.client.rpc.data.EntityData;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.common.GWTExtUtil;
import edu.stanford.bmir.protege.web.server.frame.ClassFrameTranslator;
import edu.stanford.bmir.protege.web.server.frame.NamedIndividualFrameTranslator;
import edu.stanford.bmir.protege.web.server.logging.WebProtegeLogger;
import edu.stanford.bmir.protege.web.server.logging.WebProtegeLoggerManager;
import edu.stanford.bmir.protege.web.server.owlapi.OWLAPIProject;
import edu.stanford.bmir.protege.web.server.owlapi.RenderingManager;
import edu.stanford.bmir.protege.web.server.stkosutil.common.StkosUtilBaseServlet;
import edu.stanford.bmir.protege.web.server.stkosutil.visualizer.model.StkosUtilOwlEntitySimplePropertyValue;
import edu.stanford.bmir.protege.web.server.stkosutil.visualizer.model.StkosUtilOwlEntityTreeNode;
import edu.stanford.bmir.protege.web.shared.PrimitiveType;
import edu.stanford.bmir.protege.web.shared.entity.OWLClassData;
import edu.stanford.bmir.protege.web.shared.entity.OWLNamedIndividualData;
import edu.stanford.bmir.protege.web.shared.frame.ClassFrame;
import edu.stanford.bmir.protege.web.shared.frame.NamedIndividualFrame;
import edu.stanford.bmir.protege.web.shared.frame.PropertyAnnotationValue;
import edu.stanford.bmir.protege.web.shared.frame.PropertyValue;
import edu.stanford.bmir.protege.web.shared.frame.PropertyValueState;

public class StkosUtilOwlEntityDescriptionServlet extends StkosUtilBaseServlet {
	private static final long serialVersionUID = 1L;
	public static final WebProtegeLogger LOGGER = WebProtegeLoggerManager
			.get(StkosUtilOwlEntityDescriptionServlet.class);
	public static final String JSON = "{\"success\":{0},\"msg\":{1},\"result\":{2}}";
	public static final String EM = "\"\"";
	public static final ClassFrameTranslator CLASSTRANSLATOR = new ClassFrameTranslator();
	public static final NamedIndividualFrameTranslator NAMEDINDIVIDUALTRANSLATOR = new NamedIndividualFrameTranslator();

	private HttpServletResponse resp;
	private OWLAPIProject project;

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		this.resp = resp;

		project = getProject(req.getParameter("projectId"));
		final String entityIri = req.getParameter("entityIri");
		String entityType = req.getParameter("entityType");
		EntityType et = null;
		if ("CLASS".equals(entityType)) {
			et = EntityType.CLASS;
		} else if ("NAMED_INDIVIDUAL".equals(entityType)) {
			et = EntityType.NAMED_INDIVIDUAL;
		}

		if (project == null || entityIri == null || "".equals(entityIri.trim())
				|| et == null) {
			writeJson(false, "\"Required argument can not be null!\"", EM);
		} else {
			try {
				IRI iRI = IRI.create(entityIri);
				OWLEntity owlEntity = project.getDataFactory().getOWLEntity(et,
						iRI);
				if (owlEntity == null) {
					writeJson(false, "\"The entity[" + entityIri
							+ "] may be deleted!\"", EM);
				} else {
					getDescription(owlEntity);
				}
			} catch (Exception e) {
				LOGGER.info("Getting entity[" + entityIri + "] failure.", e);
				writeJson(false, "\"Getting entity[" + entityIri
						+ "] failure! Details: " + e + "\"", EM);
			}
		}
	}

	protected void getDescription(OWLEntity owlEntity) {
		if (owlEntity == null) {
			LOGGER.info("The entity can not be null.");
			writeJson(false, "\"The entity may be deleted!\"", EM);
			return;
		}
		final StkosUtilOwlEntityTreeNode owlEntityTreeNode = new StkosUtilOwlEntityTreeNode();

		OWLEntityVisitor visitor = new OWLEntityVisitor() {
			@Override
			public void visit(OWLAnnotationProperty property) {
				System.out.println("OWLAnnotationProperty " + property);
			}

			@Override
			public void visit(OWLDatatype datatype) {
				System.out.println("OWLDatatype " + datatype);
			}

			@Override
			public void visit(OWLDataProperty property) {
				System.out.println("OWLDataProperty " + property);
			}

			@Override
			public void visit(OWLObjectProperty property) {
				System.out.println("OWLObjectProperty " + property);
			}

			@Override
			public void visit(OWLNamedIndividual individual) {
				RenderingManager rm = project.getRenderingManager();

				EntityData entityData = rm.getEntityData(individual);

				// base info
				owlEntityTreeNode.setIri(entityData.getName());
				owlEntityTreeNode.setDisplayName(entityData.getBrowserText());
				owlEntityTreeNode.setEntityType(PrimitiveType.NAMED_INDIVIDUAL);

				// properties

				NamedIndividualFrame frame = NAMEDINDIVIDUALTRANSLATOR
						.getFrame(individual, project.getRootOntology(),
								project);

				// annotation properties
				for (PropertyAnnotationValue annotation : frame
						.getAnnotationPropertyValues()) {
					if (PropertyValueState.ASSERTED.equals(annotation
							.getState())) {
						StkosUtilOwlEntitySimplePropertyValue entityPropertyValue = new StkosUtilOwlEntitySimplePropertyValue();
						entityPropertyValue.setName(annotation.getProperty()
								.toString());
						entityPropertyValue.setValue(annotation.getValue()
								.toString());
						owlEntityTreeNode.getPropertyValues().add(
								entityPropertyValue);
					}
				}

				// object properties
				for (PropertyValue logical : frame.getLogicalPropertyValues()) {
					if (PropertyValueState.ASSERTED.equals(logical.getState())) {
						StkosUtilOwlEntitySimplePropertyValue entityPropertyValue = new StkosUtilOwlEntitySimplePropertyValue();
						entityPropertyValue.setName(rm.getBrowserText(logical
								.getProperty()));
						entityPropertyValue.setValue(rm.getBrowserText(logical
								.getValue()));
						entityPropertyValue.setLogical(true);
						owlEntityTreeNode.getPropertyValues().add(
								entityPropertyValue);
					}
				}
			}

			@Override
			public void visit(OWLClass cls) {
				RenderingManager rm = project.getRenderingManager();

				OWLClassData owlClassData = rm.getRendering(cls);

				// base info
				owlEntityTreeNode.setIri(owlClassData.getEntity().getIRI()
						.toString());
				owlEntityTreeNode.setDisplayName(owlClassData.getBrowserText());
				owlEntityTreeNode.setEntityType(owlClassData.getType());

				// individuals
				List<OWLNamedIndividualData> individualsDatas = new ArrayList<OWLNamedIndividualData>();
				if (cls.isOWLThing()) {
					Set<OWLNamedIndividual> individualsInSignature = project
							.getRootOntology().getIndividualsInSignature(true);
					for (OWLNamedIndividual individual : individualsInSignature) {
						OWLNamedIndividualData owlNamedIndividualData = rm
								.getRendering(individual);
						if (owlNamedIndividualData != null) {
							individualsDatas.add(owlNamedIndividualData);
						}
					}
				} else {
					/**
					for (OWLIndividual individual : cls.getIndividuals(project
							.getRootOntology().getImportsClosure())) {
						if (individual != null && individual.isNamed()) {
						}
					}
					*/
					for (OWLClassAssertionAxiom ax : project.getRootOntology()
							.getClassAssertionAxioms(cls)) {
						OWLIndividual individual = ax.getIndividual();
						if (individual.isNamed()) {
							OWLNamedIndividualData owlNamedIndividualData = rm
									.getRendering(individual
											.asOWLNamedIndividual());
							if (owlNamedIndividualData != null) {
								individualsDatas.add(owlNamedIndividualData);
							}
						}
					}
				}
				
				for(OWLNamedIndividualData individualsData:individualsDatas){
					StkosUtilOwlEntityTreeNode owlEntityTreeNode2 = new StkosUtilOwlEntityTreeNode();
					owlEntityTreeNode2.setDisplayName(individualsData
							.getBrowserText());
					owlEntityTreeNode2.setIri(individualsData.getEntity().getIRI().toString());
					owlEntityTreeNode2
							.setEntityType(individualsData.getType());

					owlEntityTreeNode.getChildren().add(owlEntityTreeNode2);
				}
				
				ClassFrame frame = CLASSTRANSLATOR.getFrame(cls,
						project.getRootOntology(), project);

				// annotation properties
				for (PropertyAnnotationValue annotation : frame
						.getAnnotationPropertyValues()) {
					if (PropertyValueState.ASSERTED.equals(annotation
							.getState())) {
						StkosUtilOwlEntitySimplePropertyValue entityPropertyValue = new StkosUtilOwlEntitySimplePropertyValue();
						entityPropertyValue.setName(rm
								.getBrowserText(annotation.getProperty()));
						entityPropertyValue.setValue(annotation.getValue()
								.toString());
						owlEntityTreeNode.getPropertyValues().add(
								entityPropertyValue);
					}
				}

				// object properties
				for (PropertyValue logical : frame.getLogicalPropertyValues()) {
					if (PropertyValueState.ASSERTED.equals(logical.getState())) {
						StkosUtilOwlEntitySimplePropertyValue entityPropertyValue = new StkosUtilOwlEntitySimplePropertyValue();
						entityPropertyValue.setName(rm.getBrowserText(logical
								.getProperty()));
						entityPropertyValue.setValue(rm.getBrowserText(logical
								.getValue()));
						entityPropertyValue.setLogical(true);
						owlEntityTreeNode.getPropertyValues().add(
								entityPropertyValue);
					}
				}
			}
		};
		owlEntity.accept(visitor);
		writeJson(true, "\"Getting owlEntity info success!\"", JSONObject
				.fromObject(owlEntityTreeNode).toString());
	}

	protected void writeJson(boolean success, String msg, String result) {
		if (resp == null) {
			return;
		}

		msg = (msg == null || "".equals(msg.trim())) ? EM : msg.trim();
		result = (result == null || "".equals(result.trim())) ? EM : result
				.trim();

		String json = GWTExtUtil.stringFormat(JSON, String.valueOf(success),
				msg, result);
		writeJson_utf8(json, resp);
	}
}
